/*******************************************************************************
* Copyright (c) 2013 IBM Corporation and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.orion.internal.server.core.metastore;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.spec.InvalidKeySpecException;
import java.util.Arrays;
import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import org.eclipse.orion.server.core.LogHelper;
import org.eclipse.orion.server.core.resources.Base64;
/**
* A utility class to encrypt and decrypt passwords. This implementation is a simplification of
* the capability that exists in org.eclipse.equinox.security.
*
* @author Anthony Hunter
*/
public class SimpleUserPasswordUtil {
/**
* The system property name for the secure storage master password.
*/
public static final String ORION_STORAGE_PASSWORD = "orion.storage.password"; //$NON-NLS-1$
/**
* Separates salt from the encryped password.
*/
final static private char SALT_SEPARATOR = ',';
final static private String CHAR_ENCODING = "UTF-8"; //$NON-NLS-1$
final static private String ENCRYPTION_ALGORITHM = "PBEWithMD5AndDES";
public static String encryptPassword(String password) {
try {
byte[] salt = generateSalt();
byte[] encryptedPassword = encryptPassword(password.getBytes(), salt);
byte[] saltBase64 = Base64.encode(salt);
byte[] encryptedPasswordBase64 = Base64.encode(encryptedPassword);
String saltString = new String(saltBase64, CHAR_ENCODING);
String encryptedPasswordString = new String(encryptedPasswordBase64, CHAR_ENCODING);
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(saltString);
stringBuffer.append(SALT_SEPARATOR);
stringBuffer.append(encryptedPasswordString);
return stringBuffer.toString();
} catch (NoSuchAlgorithmException e) {
LogHelper.log(e);
} catch (UnsupportedEncodingException e) {
LogHelper.log(e);
}
return null;
}
private static byte[] decryptPassword(byte[] password, byte[] salt) {
try {
byte[] decryptedPassword = null;
PBEKeySpec pbeKeySpec = new PBEKeySpec(getPassword(), salt, 1024, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ENCRYPTION_ALGORITHM);
SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 10);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.DECRYPT_MODE, secretKey, pbeParameterSpec);
decryptedPassword = cipher.doFinal(password);
return decryptedPassword;
} catch (NoSuchAlgorithmException e) {
LogHelper.log(e);
} catch (InvalidKeySpecException e) {
LogHelper.log(e);
} catch (InvalidKeyException e) {
LogHelper.log(e);
} catch (IllegalBlockSizeException e) {
LogHelper.log(e);
} catch (BadPaddingException e) {
LogHelper.log(e);
} catch (NoSuchPaddingException e) {
LogHelper.log(e);
} catch (InvalidAlgorithmParameterException e) {
LogHelper.log(e);
}
return null;
}
private static byte[] encryptPassword(byte[] password, byte[] salt) {
try {
byte[] encryptedPassword = null;
PBEKeySpec pbeKeySpec = new PBEKeySpec(getPassword(), salt, 1024, 256);
SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(ENCRYPTION_ALGORITHM);
SecretKey secretKey = secretKeyFactory.generateSecret(pbeKeySpec);
PBEParameterSpec pbeParameterSpec = new PBEParameterSpec(salt, 10);
Cipher cipher = Cipher.getInstance(ENCRYPTION_ALGORITHM);
cipher.init(Cipher.ENCRYPT_MODE, secretKey, pbeParameterSpec);
encryptedPassword = cipher.doFinal(password);
return encryptedPassword;
} catch (NoSuchAlgorithmException e) {
LogHelper.log(e);
} catch (InvalidKeySpecException e) {
LogHelper.log(e);
} catch (InvalidKeyException e) {
LogHelper.log(e);
} catch (IllegalBlockSizeException e) {
LogHelper.log(e);
} catch (BadPaddingException e) {
LogHelper.log(e);
} catch (NoSuchPaddingException e) {
LogHelper.log(e);
} catch (InvalidAlgorithmParameterException e) {
LogHelper.log(e);
}
return null;
}
private static byte[] generateSalt() throws NoSuchAlgorithmException {
SecureRandom secureRandom = SecureRandom.getInstance("SHA1PRNG");
byte[] salt = new byte[8];
secureRandom.nextBytes(salt);
return salt;
}
private static boolean verifyPassword(String password, byte[] encryptedPassword, byte[] salt) throws NoSuchAlgorithmException, InvalidKeySpecException {
byte[] checkEncryptedPassword = encryptPassword(password.getBytes(), salt);
return Arrays.equals(encryptedPassword, checkEncryptedPassword);
}
public static String decryptPassword(String encryptedText) {
try {
int saltPos = encryptedText.indexOf(SALT_SEPARATOR);
if (saltPos == -1) {
throw new RuntimeException("Invalid Data Format");
}
byte[] saltBase64 = encryptedText.substring(0, saltPos).getBytes(CHAR_ENCODING);
byte[] encryptedPasswordBase64 = encryptedText.substring(saltPos + 1).getBytes(CHAR_ENCODING);
byte[] salt = Base64.decode(saltBase64);
byte[] encryptedPassword = Base64.decode(encryptedPasswordBase64);
byte[] decryptedPassword = decryptPassword(encryptedPassword, salt);
return new String(decryptedPassword);
} catch (UnsupportedEncodingException e) {
LogHelper.log(e);
}
return null;
}
public static boolean verifyPassword(String password, String encryptedText) {
try {
int saltPos = encryptedText.indexOf(SALT_SEPARATOR);
if (saltPos == -1) {
throw new RuntimeException("Invalid Data Format");
}
byte[] saltBase64 = encryptedText.substring(0, saltPos).getBytes(CHAR_ENCODING);
byte[] encryptedPasswordBase64 = encryptedText.substring(saltPos + 1).getBytes(CHAR_ENCODING);
byte[] salt = Base64.decode(saltBase64);
byte[] encryptedPassword = Base64.decode(encryptedPasswordBase64);
return verifyPassword(password, encryptedPassword, salt);
} catch (NoSuchAlgorithmException e) {
LogHelper.log(e);
} catch (InvalidKeySpecException e) {
LogHelper.log(e);
} catch (UnsupportedEncodingException e) {
LogHelper.log(e);
}
return false;
}
private static char[] getPassword() {
String password = System.getProperty(ORION_STORAGE_PASSWORD, "unspecified"); //$NON-NLS-1$
return password.toCharArray();
}
public static void main(String[] args) {
if (args.length > 2 && "-encode".equals(args[0])) {
System.out.println(encryptPassword(args[1]));
} else if (args.length > 2 && "-decode".equals(args[0])) {
System.out.println(decryptPassword(args[1]));
} else {
System.out.println("Usage: java SimpleUserPasswordUtil <-encode || -decode> value");
}
}
}